package com.gzsxy.config;

import com.gzsxy.exception.AuthExceptionEntryPoint;
import com.gzsxy.exception.CustomAccessDeniedHandler;
import com.gzsxy.handler.CustomLogoutSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

/**
 * @author xiaolong
 * @version 1.0
 * @description: 资源Server端  WebSecurityConfig优先级高于ResourceServerConfig
 * @date 2021/11/4 20:02
 */
@Configuration
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {


    private static final String DEFAULT_RESOURCE_ID = "esjy_resource";


        @Value("${mayikt.appid}")
        private String mayiktAppId;
        @Value("${mayikt.appsecret}")
        private String mayiktAppSecret;

        @Autowired
        CustomAccessDeniedHandler customAccessDeniedHandler;

        @Autowired
        CustomLogoutSuccessHandler logoutHandler;

        @Autowired
        private TokenStore tokenStore;



        //认证白名单
        private static String AUTH_WHITELIST = ""
                + "/swagger**/**,/swagger-ui.html,/resources/**,/configuration**/**"
                +"/oauth/**,"
                +"/druid/**"
                +"/webjars/**,/static/**,/lib/**,/**/*.js,/**/*.css,/favicon.ico,"
                +"/**/*.png,/**/*.jpg,/**/*.bmp,";


        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }







        //资源服务令牌解析服务
        @Primary
        @Bean
        public RemoteTokenServices remoteTokenServices() {
           //使用远程服务请求授权服务器校验token，必须指定校验token的url、client_id,client_secret
            final RemoteTokenServices tokenServices = new RemoteTokenServices();
            //设置授权服务器check_token端点完整地址
            tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
            //设置客户端id与secret，注意：client_secret值不能使用passwordEncoder加密！
            tokenServices.setClientId(mayiktAppId);
            tokenServices.setClientSecret(mayiktAppSecret);
            return tokenServices;
        }

        //授权
        @Override
        public void configure(HttpSecurity http) throws Exception {
            //设置创建session策略
            http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
            //@formatter:off
            //所有请求必须授权
            http.authorizeRequests()
                    //需要orderManager权限才能访问这个接口
                    .antMatchers("/getMember/**").hasAuthority("orderManager")
                    //客户端id资源作用域all
                    .antMatchers("/**").access("#oauth2.hasScope('all')")
                    .anyRequest().authenticated()  //其他请求需要认证才能请求
                    .and().logout()
                    .logoutUrl("/oauth/logout")
                     // 注销成功自定义处理
                    .logoutSuccessHandler(logoutHandler)
                    .and().csrf().disable();
            //@formatter:on
        }


        /**   资源安全配置相关
         *   resourceId: 用于分配给可授予的clientId
         *   stateless: 标记资源仅允许基于令牌的身份验证
         *   authenticationEntryPoint: 认证异常流程处理返回-token失效
         *   tokenExtractor: token提前方式
         *   accessDeniedHander:   授权失败且要求特定的内容类型相应 -没有权限
         */
        @Override
        public void configure(ResourceServerSecurityConfigurer resources) {
            //资源id
            resources.resourceId(DEFAULT_RESOURCE_ID)

                    //令牌存储模式   （基于redis存储的话就不需要验证令牌服务，因为redis中又相关用户数据）
                    .tokenStore(tokenStore)
                    //验证令牌的服务  （令牌基于内存方式需要手动验证令牌）
//                    .tokenServices(remoteTokenServices())
                    //认证异常流程处理返回-token失效
                    .authenticationEntryPoint(new AuthExceptionEntryPoint())
                    //授权失败且要求特定的内容类型相应 -没有权限
                    .accessDeniedHandler(customAccessDeniedHandler)
                    .stateless(true);
        }



    //令牌存储策略
//    @Bean
//    public TokenStore tokenStore(){
//        //内存方式，生产普通令牌
//        return new InMemoryTokenStore();
//    }
}



